home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1987 / 04 / brown1ls.lst next >
File List  |  1987-03-12  |  40KB  |  917 lines

  1. #define PGM_ID "SILOAM CI-C86 Ver. of 11/22/86 for PC-DOS 2.x+"
  2.  
  3. /*     An Adaptive Template Matching Image Categorizer
  4.  *        (An Experimental Computer Vision Program)
  5.  *
  6.  *      This program implements a trainable pattern classifier as
  7.  *  a committee network of threshold logic units.  It learns to
  8.  *  recognize patterns by being trained from a set of prototype
  9.  *  patterns presented in a training file.  The training file is
  10.  *  organized as a set of visual images represented as an orthogonal
  11.  *  array of picture elements, or pixels.  Each pixel is a number
  12.  *  representing the gray-scale value of that point in the image.
  13.  *  Associated with each pattern is a number, or tag, that
  14.  *  represents the category to which that pattern belongs.
  15.  *
  16.  *        R. J. Brown
  17.  *        Elijah Laboratories International
  18.  *        5225 N.W. 27th Court
  19.  *        Margate, FL 33063
  20.  *        (305) 979-1567
  21.  *
  22.  *   Ownership: I hereby place this program in the public domain.
  23.  *
  24.  *   System:    Red River ATlas 10 MHz 80286 IBM-PC/AT clone
  25.  *
  26.  *   Compiler:  C86 Version 2.30H; Computer Innovations, Inc.
  27.  *
  28.  *  "And as Jesus passed by, he saw a man which was BLIND from his birth...
  29.  *  And said unto him, Go, wash in the pool of Siloam...  He went his way
  30.  * therefore, and washed, and came SEEING."
  31.  *                  John 9:1-7
  32.  */
  33.  
  34. #include "stdio.h"              /* needed for stream input/output       */
  35.  
  36. #define FALSE     0             /* boolean constant for 'false'         */
  37. #define TRUE     !FALSE         /* boolean constant for 'true'          */
  38.  
  39. #define NULL ((int *)0)         /* the pointer to nowhere               */
  40.  
  41. #define void                    /* function that returns no value       */
  42.  
  43. #define forall(index,limit)\
  44.         for((index)=0;(index)<(limit);(index)++)    /* looping word     */
  45.  
  46. #define kase(id,stmt)   \
  47.         case(id): {     \
  48.             stmt;       \
  49.             break;      \
  50.             }           /* shorthand form for case statement            */
  51.  
  52. #define u(x) ((unsigned)(x))    /* shorthand for '(unsigned)' cast      */
  53.  
  54. typedef unsigned char  byte;    /* an 8-bit byte of storage             */
  55. typedef unsigned int   word;    /* a 16-bit word of storage             */
  56.  
  57. typedef word     boolean;       /* a decision variable,
  58.                                  * 'true' or 'false value only */
  59.  
  60. typedef ELTYPE     element;     /* an element is a real number          */
  61. typedef DOTYPE     DOT;         /* type of a dot product may be bigger! */
  62. typedef element   *vector;      /* a vector is a set of elements        */
  63.  
  64. typedef vector    tlu;          /* a tlu is a vector                    */
  65.  
  66. typedef struct {                /* the collection of                    */
  67.         tlu     *wtpt;          /* a set of tlu weight points,          */
  68.         DOT     *dot;           /* and dot product save cells           */
  69.         }         committee;    /* is a committee                       */
  70.  
  71. typedef char      *pointer;     /* a general pointer to whatever...     */
  72.  
  73.  
  74. /************************************************************************
  75.  *
  76.  *         G l o b a l    V a r i a b l e    D e f i n i t i o n s
  77.  *
  78.  ************************************************************************/
  79.  
  80. FILE    *pat,           /* the input training pattern file              */
  81.         *fopen();       /* the file opener                              */
  82.  
  83. byte    patname[64],    /* ascii filename of input file                 */
  84.         *index();       /* string search library function               */
  85.  
  86. int     ncom,           /* number of committees in the network          */
  87.         patwide,        /* pattern width in pixels                      */
  88.         pathite,        /* pattern height in pixels                     */
  89.         pats_so_far,    /* how many patterns in file so far             */
  90.         pats_missed,    /* how many patterns were mis-recognized so far */
  91.         missed,         /* # of patterns missed on this pass            */
  92.         tlus_trained,   /* how many tlu's have been adjusted so far     */
  93.         npass,          /* number of current pass thru pattern file     */
  94.         log_level,      /* level of detail for run-time logging         */
  95.         dim,            /* number of elements in a vector (dimension)   */
  96.         ntlu,           /* number of tlus per committee                 */
  97.         corr_incr,      /* fixed increment correction constant          */
  98.         *vote;          /* pointer to vote count array                  */
  99.  
  100. boolean goofed,         /* mis-recognition indicator for training loop  */
  101.         start_over,     /* select start over on error training strategy */
  102.         absolute,       /* flag for absolute correction training method */
  103.         *decsn,         /* pointer to network's decision array          */
  104.         *class;         /* pointer to class (category) array            */
  105.  
  106.  
  107. DOT     patmag;         /* pattern magnitude (used for training)        */
  108.  
  109. element fraction,       /* correction fraction for training             */
  110.         maxel=0;        /* maximum element in a weight point            */
  111.         radius;         /* average radius (distance from origin)
  112.                          * of tlu weight point at initialization */
  113.  
  114. vector  pattern;        /* pointer to current input pattern             */
  115.  
  116. committee *net;         /* pointer to network as an array of committees */
  117.  
  118.  
  119. /************************************************************************
  120.  *
  121.  *                L i b r a r y    R o u t i n e s
  122.  *
  123.  ************************************************************************/
  124.  
  125. extern float   atof();  /* ascii to float library conversion routine    */
  126. extern double  sqrt();  /* square root library function                 */
  127. extern pointer calloc();/* memory allocation library function           */
  128. extern long    time();  /* benchmark timing routine                     */
  129.  
  130.  
  131. /************************************************************************
  132.  *
  133.  *      B A N N E R   --    D i s p l a y    P r o g r a m   I. D.
  134.  *
  135.  ************************************************************************/
  136.  
  137. void banner() { /* display program identification information           */
  138.  
  139.     printf("\n%s",PGM_ID);     /* Program Identification is #define'd
  140.                                 * at top of source file */
  141.  
  142.     printf("\nWritten by:  R. J. Brown, Elijah Laboratories Intn'l");
  143.     printf("\nThis program is in the Public Domain.\n");
  144. }
  145.  
  146.  
  147. /************************************************************************
  148.  *
  149.  *              H E L P    D i s p l a y    S c r e e n
  150.  *
  151.  ************************************************************************/
  152.  
  153. void help() {   /* some user friendly help for the uninitiated !        */
  154.  
  155.     printf("Simple Image Learning On Adaptive Machinery\n");
  156.     printf("An Adaptive Template Matching Image Categorizer\n");
  157.     printf("\n");
  158.     printf("    R. J. Brown, Elijah Laboratories International\n");
  159.     printf("    5150 W. Copans Rd. Suite 1135, Margate FL 33063\n");
  160.     printf("\n");
  161.     printf("usage:       siloam <options> filename[.ext]\n\n");
  162.     printf("where:  filename -- is the input pattern file.\n\n");
  163.     printf("options:  -r##.# -- gives initialization radius.\n");
  164.     printf("            -t## -- gives number of TLUs per committee.\n");
  165.     printf("              -o -- start over on error,\n\n");
  166.     printf("choose one: -i## -- fixed increment correction, ## = incr.\n");
  167.     printf("              -a -- absolute correction.\n");
  168.     printf("          -f##.# -- fractional correction, ##.# is lambda.\n");
  169.     printf("             -l# -- logging level: 0=least; 3=most.\n");
  170.     exit(0);
  171. }
  172.  
  173.  
  174. /************************************************************************
  175.  *
  176.  *      S I G N  --  T h e   S i g n   O f   A n   E l e m e n t   +/- 1
  177.  *
  178.  ************************************************************************/
  179.  
  180. int sign(x)     /* return the sign of a number as plus or minus one     */
  181. element x;      /* argument is an element                               */
  182. {
  183.     return( x<(element)0 ? -1   /* if number is negative, return -1     */
  184.                          :  1 );/* else return +1                       */
  185. }
  186.  
  187.  
  188. /************************************************************************
  189.  *
  190.  *    I S I G N  --  T h e   S i g n   O f   A n   I n t e g e r   +/- 1
  191.  *
  192.  ************************************************************************/
  193.  
  194. int isign(x)    /* return the sign of a number as plus or minus one     */
  195. int x;          /* argument is an integer                               */
  196. {
  197.     return( x<0  ? -1           /* if number is negative, return -1     */
  198.                  :  1 );        /* else return +1                       */
  199. }
  200.  
  201.  
  202. /************************************************************************
  203.  *
  204.  *   A B S  --  A b s o l u t e   V a l u e   Of   A n   E l e m e n t
  205.  *
  206.  ************************************************************************/
  207.  
  208. element eabs(x)     /* the absolute value of an element                 */
  209. element x;          /* argument is an element                           */
  210. {
  211.     return( x<0 ? -x      /* if number is negative, make it positive    */
  212.                 :  x );   /* else return it like it is                  */
  213. }
  214.  
  215.  
  216. /************************************************************************
  217.  *
  218.  *  I A B S  --  A b s o l u t e   V a l u e   O f   A n   I n t e g e r
  219.  *
  220.  ************************************************************************/
  221.  
  222. int iabs(x)          /* the absolute value of an integer                */
  223. int x;               /* argument is an integer                          */
  224. {
  225.     return( x<0 ? -x        /* if number is negative, make it positive  */
  226.                 :  x );     /* else return it like it is                */
  227. }
  228.  
  229. /************************************************************************
  230.  *
  231.  *              A L P H A  --  S t e p   F u n c t i o n
  232.  *
  233.  ************************************************************************/
  234.  
  235. int alpha(x)        /* step function return zero or one                 */
  236. int x;              /* argument is an integer (in this program...)      */
  237. {
  238.     return( x>0 ? 1        /* if argument strictly positive, return one */
  239.                 : 0 );     /* else return zero                          */
  240. }
  241.  
  242.  
  243. /************************************************************************
  244.  *
  245.  *        M O V E  --  S t r i n g   M o v e   F u n c t i o n
  246.  *
  247.  ************************************************************************/
  248.  
  249. char *move(src,dst)     /* move a string returning ptr to end of result */
  250. char *src,*dst;         /* pointers to source & destination strings     */
  251. {
  252.     while(0!=((*dst++)=(*src++)));  /* copy bytes until end of source   */
  253.     return(--dst);                  /* return ptr to end of destination */
  254. }
  255.  
  256.  
  257. /************************************************************************
  258.  *
  259.  *    R A D I U S    S T A T I S T I C S  --  S u m m a r y    I n f o
  260.  *
  261.  ************************************************************************/
  262.  
  263. void radius_statistics() {   /* show how weight points are distributed  */
  264.  
  265.     element r,          /* current radius accumulator                   */
  266.             *pe;        /* pointer to current element                   */
  267.     float   mu=0,       /* mean of radii                                */
  268.             sigma=0;    /* standard deviation of radii                  */
  269.  
  270.     committee *pc=net;  /* pointer to current committee                 */
  271.  
  272.     vector  *pt;        /* pointer to current tlu                       */
  273.  
  274.     int     c,              /* committee loop counter                   */
  275.             t,              /* tlu loop counter                         */
  276.             e,              /* element loop counter                     */
  277.             n=ncom*ntlu;    /* number of tlu's altogether               */
  278.  
  279.     forall(c,ncom) {            /* for all committees...                */
  280.         pt=pc++->wtpt;              /* point to first tlu               */
  281.         forall(t,ntlu) {            /* for all tlu's...                 */
  282.             pe=*pt++;                   /* point to first element       */
  283.             r=0.;                       /* initialize radius tally      */
  284.             forall(e,dim) {             /* for all elements...          */
  285.                 r+=(*pe)*(*pe);             /* accumulate radius sqr'd  */
  286.                 pe++;                       /* point to next element    */
  287.             }
  288.             mu+=sqrt((float)r);         /* accumulate sum of radii      */
  289.             sigma+=(float)r;            /* accumulate variance variable */
  290.         }
  291.     }
  292.     mu/=(float)n;               /* divide to get overall average radius */
  293.     sigma-=mu*mu*n;             /* compute variance                     */
  294.     sigma=sqrt(sigma)/mu;       /* compute standard deviation           */
  295.  
  296.     printf("\nmean of the radii:  %f",mu);      /* print statistical    */
  297.     printf("\nstandard deviation: %f",sigma);   /* summary of weight    */
  298.     printf("\n");                               /* point distribution   */
  299. }
  300.  
  301.  
  302. /************************************************************************
  303.  *
  304.  *      R E A D   H E A D E R  --  R e a d    F i l e    H e a d e r
  305.  *
  306.  ************************************************************************/
  307.  
  308. void read_header()          /* read training file header information    */
  309. {
  310.  
  311.     rewind(pat);                    /* rewind pattern file              */
  312.     pats_so_far=0;                  /* reset pattern sequence counter   */
  313.  
  314.     fscanf(pat,                     /* header comes from pattern file   */
  315.  
  316.            "hdr %d %d %d \n",       /* header must start with 'hdr'
  317.                                      * then read header information
  318.                                      * composed of three numbers */
  319.  
  320.            /* put this information into the following global variables  */
  321.  
  322.            &ncom,                   /* number of committees in network  */
  323.            &patwide,                /* pattern width in pixels          */
  324.            &pathite);               /* pattern height in pixels         */
  325. }
  326.  
  327.  
  328. /************************************************************************
  329.  *
  330.  *   R A N D O M   --   R a n d o m    N u m b e r   G e n e r a t o r
  331.  *
  332.  ************************************************************************/
  333.  
  334. element random() {      /* generate a uniformly distributed
  335.                          * random number from the open interval (0...1) */
  336.  
  337.     return(rand()/16384.);       /* return scaled random integer        */
  338. }
  339.  
  340.  
  341. /************************************************************************
  342.  *
  343.  *      I N I T    V A L  --  I n i t i a l   E l e m e n t   V a l u e
  344.  *
  345.  ************************************************************************/
  346.  
  347. element init_val(radius)    /* generate init'l value for element a tlu  */
  348. element radius;             /* the avarage radius of a weight point     */
  349. {
  350.  
  351.     return(                                     /* return the           */
  352.         (radius*sqrt(3.))/(sqrt((float)dim))    /* average weight value */
  353.         * (2.*random()-1)                       /* scaled randomly by a */
  354.     );                                          /* uniform distribution */
  355. }
  356.  
  357.  
  358. /************************************************************************
  359.  *
  360.  *   I N I T I A L I Z E  --  A l l o c a t e    S t o r a g e,  E t c.
  361.  *
  362.  ************************************************************************/
  363.  
  364. void initialize() {     /* allocate & initialize network array storage  */
  365.  
  366.     committee *pc;      /* pointer to current committee of network      */
  367.     tlu       *pt;      /* pointer to current tlu of committee          */
  368.     element   *pe,      /* pointer to current element of tlu            */
  369.                x;       /* current initialization weight value          */
  370.  
  371.     int c,              /* committee index in network                   */
  372.         t,              /* tlu index in committee                       */
  373.         e;              /* element index in tlu                         */
  374.  
  375.     printf("\ninitializing");   /* say what's taking so long !          */
  376.  
  377.     dim=patwide*pathite+1;      /* number of elements in a tlu          */
  378.  
  379.     pattern=(vector)calloc(u(dim),          /* allocate the pattern     */
  380.                    u(sizeof(element)));     /* vector                   */
  381.  
  382.     class=(boolean *)calloc(u(ncom),    /* allocate the class array     */
  383.                  u(sizeof(boolean)));   /* which will contain the
  384.       * desired decision bits from the committees, as read from the
  385.       * training file.  the actual verdict of the network will be
  386.       * compared with this to see if training is required. */
  387.  
  388.     vote=(int *)calloc(u(ncom),     /* allocate the votes array         */
  389.                 u(sizeof(int)));    /* which will contain the
  390.                                      * count of votes for each
  391.                                      * committee. */
  392.  
  393.     decsn=(boolean *)calloc(u(ncom),    /* allocate the decision        */
  394.                  u(sizeof(boolean)));   /* array which will contain
  395.                                          * the bits of the answer,
  396.                                          * one bit per committee. */
  397.  
  398.     pc=net=(committee *)calloc(u(ncom),    /* allocate the network      */
  399.                   u(sizeof(committee)));   /* as an array of committees */
  400.  
  401.     forall(c,ncom) {            /* for all committees in the network... */
  402.  
  403.         pc->wtpt=pt=(tlu *)calloc(u(ntlu),  /* allocate a committee     */
  404.                            u(sizeof(tlu))); /* as an array of tlu's     */
  405.  
  406.         pc++->dot=(DOTYPE *)calloc(u(ntlu),     /* together with dot    */
  407.                          u(sizeof(DOT)));       /* product save cells   */
  408.  
  409.         forall(t,ntlu) {        /* for all tlu's in the committee...    */
  410.  
  411.             pe=*pt++=(element *)calloc(u(dim),      /* allocate a tlu   */
  412.                             u(sizeof(element)));    /* as an array
  413.                                                      * of elements */
  414.  
  415.             forall(e,dim) {                     /* for each weight...   */
  416.                 if(radius==0) *pe++=(e!=0);     /* grow connections?    */
  417.                 else {                          /* or adjust weights?   */
  418.                     x=eabs(*pe++=init_val(      /* adjust, get initial  */
  419.                               (element)radius));/* weight value         */
  420.                     if(x>maxel) maxel=x;        /* update max magnitude */
  421.                 }    
  422.             }
  423.   /* initialize each element to a random value such that the average
  424.    * radius, or distance from the origin, of each weight point is 'radius'.
  425.    * this will produce a distribution of weight points clustered near the
  426.    * surface of a hyper-sphere as the starting condition. If the radius is
  427.    * zero, then all weights will be set to zero except for the threshold
  428.    * setting weight.  This is analogous to forcing the program to grow new
  429.    * interneural connections on an as-needed basis, supposedly just like
  430.    * the real brain does! */
  431.         }
  432.     }
  433.     printf("\n");       /* perform new-line when initialize is done     */
  434. }
  435.  
  436.  
  437. /************************************************************************
  438.  *
  439.  *      D O T P R O D   --   F o r m    A   D o t    P r o d u c t
  440.  *
  441.  ************************************************************************/
  442.  
  443. DOT dotprod(x,y)            /* form the scalar product of two vectors   */
  444. vector  x,y;                /* both arguments are vectors               */
  445. {
  446.     DOT z=0;                /* result accumulator, initialized to zero  */
  447.     int i;                  /* element index, used as loop counter      */
  448.  
  449.     forall(i,dim)           /* for all elements in each vector...       */
  450.         z+=(*x++)*(*y++);           /* compute the dot product          */
  451.  
  452.     return(z);              /* return it to the caller                  */
  453. }
  454.  
  455.  
  456. /************************************************************************
  457.  *
  458.  *  R E A D   C L A S S  --  R e a d   T h e   C l a s s   T a g
  459.  *
  460.  ************************************************************************/
  461.  
  462. boolean read_class() {      /* read the class tag number for the image  */
  463.  
  464.     int       i,            /* loop counter for index in class array    */
  465.               tmp;          /* temp cell to hold decimal category       */
  466.     boolean  *pcl=class;    /* pointer to class (category) array        */
  467.  
  468.     if(fscanf(pat,"%d",&tmp)!=1)    /* read the pattern category        */
  469.         return(FALSE);              /* return FALSE for end of file     */
  470.  
  471.     forall(i,ncom) {                /* for each committee in network    */
  472.         *pcl++=tmp&1;               /* extract desired committee output */
  473.         tmp>>=1;                    /* advance to next committee        */
  474.     }
  475.  
  476.     *pcl=1;                 /* augment with a 1 to prevent singularity  */
  477.     pats_so_far++;          /* update pattern sequence counter          */
  478.  
  479.     return(TRUE);           /* return TRUE if class read successfully   */
  480. }
  481.  
  482.  
  483. /************************************************************************
  484.  *
  485.  *   R E A D   P A T T E R N  --  R e a d   N e x t   P a t t e r n
  486.  *
  487.  ************************************************************************/
  488.  
  489. boolean read_pattern() {    /* read next pattern from training file     */
  490.  
  491.     int       i,j;          /* loop counters for row & column of image  */
  492.     element  *pe=pattern;   /* pointer to element of pattern vector     */
  493.     float     tmp;          /* temp cell for input conversion           */
  494.  
  495.     forall(i,patwide)                   /* for each row in the image,   */
  496.         forall(j,pathite)               /* for each pixel in that row,  */
  497.             if( fscanf(pat,"%f",&tmp)   /* input value of pixel         */
  498.                 !=1 )  return(FALSE);   /* return FALSE if end-of-file  */
  499.             else *pe++=(element)tmp;    /* convert to type element      */
  500.  
  501.     return( read_class() );     /* read in its class as an array
  502.       * of correct decisions for each committee in the network.  If the
  503.       * entire pattern is read, together with its class, return TRUE. */
  504. }
  505.  
  506.  
  507. /************************************************************************
  508.  *
  509.  *       C O U N T   V O T E S  --  C o u n t   T h e   V o t e s
  510.  *
  511.  ************************************************************************/
  512.  
  513. int count_votes(pc) /* count the votes for each tlu in a committee      */
  514. committee  *pc;     /* second parameter is a pointer to committee       */
  515. {
  516.     DOT *pd=pc->dot;        /* dot product save cell pointer            */
  517.     tlu *pt=pc->wtpt;       /* tlu pointer                              */
  518.  
  519.     int     ti,             /* tlu index (loop counter)                 */
  520.             count=0;        /* the count of votes for the committee     */
  521.  
  522.     forall(ti,ntlu)                         /* forall tlus in committee */
  523.         count+=sign(                        /* count votes as + or -    */
  524.             *pd++=                          /* & save dot product as    */
  525.                 dotprod(*pt++,pattern)      /* weight point dotted with */
  526.         );                                  /* pattern vector           */
  527.     return(count);          /* return tally                             */
  528. }
  529.  
  530.  
  531. /************************************************************************
  532.  *
  533.  *     R E C O G N I Z E  --  R e c o g n i z e   A   P a t t e r n
  534.  *
  535.  ************************************************************************/
  536.  
  537. void recognize() {  /* recognize a pattern by taking the decision
  538.                      * of each committee to be a bit in the category
  539.                      * number for the pattern
  540.                      */
  541.  
  542.     int     i,          /* loop counter                                 */
  543.             *pv=vote;   /* pointer to vote count array                  */
  544.  
  545.     boolean *pdec=decsn;/* pointer to decision array.
  546.                          * this holds the decision bits for each
  547.                          * of the committees in the network.
  548.                          */
  549.  
  550.     committee *pc=net;  /* pointer to current committee in network      */
  551.  
  552.     forall(i,ncom)       /* for all committees in the network...         */
  553.         *pdec++=alpha(*pv++=count_votes(pc++)); /* how many votes ?     */
  554. }
  555.  
  556.  
  557. /************************************************************************
  558.  *
  559.  *   $ G E T   W E A K   T L U  --  S w a y   W h i c h   O n e  ?
  560.  *
  561.  ************************************************************************/
  562.  
  563. int get_weak_tlu(ci)    /* choose tlu most vulnerable to be swayed      */
  564. int ci;                 /* argument is committee index                  */
  565. {
  566.     int     weak=0,             /* index of weakest tlu so far          */
  567.             sv=isign(vote[ci]), /* sign of committee's vote             */
  568.             ti;                 /* tlu index                            */
  569.  
  570.     DOT *pd=(&net[ci])->dot,        /* pointer to dot product array     */
  571.         conviction=INFINITY,        /* lowest conviction so far         */
  572.         d;                          /* saved dot product value          */
  573.  
  574.     forall(ti,ntlu) {   /* for all of the tlu's in this committee...    */
  575.  
  576.         d=pd[ti];            /* get the saved dot product value         */
  577.  
  578.         if(sign(d)==sv) {              /* if tlu voted incorrectly      */
  579.  
  580.             if(eabs(d)<conviction) {         /* and if this tlu has the
  581.               * least conviction of any that have been examined so far, */
  582.  
  583.                 weak=ti;    /* then remember it as the best one so
  584.                   * far to adjust to sway the vote of this committee. */
  585.  
  586.                 conviction=eabs(d);     /* update lowest conviction     */
  587.             }
  588.         }
  589.     }
  590.     return(weak);       /* return subscript of weakest tlu in committee */
  591. }
  592.  
  593.  
  594. /************************************************************************
  595.  *
  596.  *  A D J U S T M E N T  --  C o r r e c t i o n   C o e f f i c i e n t
  597.  *
  598.  ************************************************************************/
  599.  
  600. element adjustment(ci,ti)   /* compute correction coefficient           */
  601. int     ci,                 /* committee index                          */
  602.         ti;                 /* tlu index                                */
  603. {
  604.     DOT d=(&net[ci])->dot[ti];          /* saved dot product            */
  605.  
  606.     if(corr_incr)                       /* fixed increment correction   */
  607.         return(corr_incr*sign(d));
  608.  
  609.     if(absolute)                        /* absolute correction          */
  610.         return((int)(d/patmag)+sign(d));
  611.  
  612.     if(fraction)                        /* fractional correction        */
  613.         return(d*fraction/patmag);
  614.  
  615.     return(abort("No correction method specified."));
  616. }
  617.  
  618.  
  619. /************************************************************************
  620.  *
  621.  *      A D J U S T  --  C h a n g e   T L U ' s   W e i g h t s
  622.  *
  623.  ************************************************************************/
  624.  
  625. void adjust(ci,ti)  /* adjust the weights of a single tlu               */
  626. int ci,             /* committee index                                  */
  627.     ti;             /* tlu index                                        */
  628. {
  629.     vector pw=(&net[ci])->wtpt[ti],     /* pointer to a weight          */
  630.            pp=pattern;                  /* pointer to a pixel           */
  631.  
  632.     element lambda=adjustment(ci,ti),   /* the correction coefficient   */
  633.             wt,awt;                     /* temps for max weight point   */
  634.  
  635.     int    i;                           /* element index & loop counter */
  636.  
  637.     tlus_trained++;                     /* count adjustment of tlu      */
  638.  
  639.     forall(i,dim) {                             /* for each coefficient */
  640.         wt=(*pw++)-=lambda*(*pp++);             /* adjust weights       */
  641.         awt=eabs(wt);                           /* save magnitude       */
  642.         if(maxel<awt) {                         /* new maximum ???      */
  643.             maxel=awt;                          /* yes, update max elem */
  644.             if(log_level) {                     /* if any logging,      */
  645.                 printf("\nmaxel=%f",            /* then display the     */
  646.                          (float)maxel);         /* new maximum value    */
  647.             }
  648.         }
  649.     }
  650.  
  651.     if(log_level>=3) 
  652.         printf("\n        com=%d    tlu=%d    lambda=%g",
  653.                           ci,ti,(float)lambda);
  654. }
  655.  
  656.  
  657. /************************************************************************
  658.  *
  659.  * S W A Y   T L U S  --  S w a y   T L U s   T o   C h a n g e   V o t e
  660.  *
  661.  ************************************************************************/
  662.  
  663. void sway_tlus(ci)  /* sway enough tlu's to change the vote             */
  664. int ci;             /* parameter is committee index                     */
  665. {
  666.     int i,                          /* loop counter                     */
  667.         lost_by=iabs(vote[ci]/2)+1, /* how many votes we lost by        */
  668.         weak_tlu;                   /* weakest wrong tlu in committee   */
  669.  
  670.     DOT *pd=(&net[ci])->dot;        /* pointer to dot product array     */
  671.  
  672.     forall(i,lost_by) {   /* do this enough times to sway the vote...   */
  673.  
  674.         weak_tlu=get_weak_tlu(ci);  /* find most vulnerable tlu         */
  675.  
  676.         adjust(ci,weak_tlu);        /* adjust its weights to change
  677.                                      * its mind about the pattern */
  678.         pd[weak_tlu]=-sign(pd[weak_tlu]); /* flip sign of dot product
  679.           * so this tlu won't be considered again in this loop */
  680.     }
  681. }
  682.  
  683.  
  684. /************************************************************************
  685.  *
  686.  *      S H O W   B I T S  --  D i s p l a y   B i t s   O n   C R T
  687.  *
  688.  ************************************************************************/
  689.  
  690. void show_bits(ps,pb)   /* display a bit vector on the screen           */
  691. char    *ps;            /* the label for the bit vector                 */
  692. boolean *pb;            /* the pointer to the bit vector                */
  693. {
  694.     int i,              /* loop counter                                 */
  695.         k=1,            /* power of two                                 */
  696.         v=0;            /* value accumulator                            */
  697.  
  698.     forall(i,ncom) {        /* for all committees                       */
  699.         if(*pb++) v+=k;     /* convert binary to decimal                */
  700.         k<<=1;              /* advance to next bit                      */
  701.     }
  702.     printf("    %s %d",ps,v);     /* display label and value            */
  703. }
  704.  
  705.  
  706. /************************************************************************
  707.  *
  708.  *      T R A I N  --  T r a i n    T h e   N e t w o r k
  709.  *
  710.  ************************************************************************/
  711.  
  712. train() {       /* train the network to recognize the pattern           */
  713.  
  714.     int     ci;     /* committee index                                  */
  715.  
  716.     goofed=FALSE;       /* give benefit of doubt -- assume didn't goof  */
  717.  
  718.     patmag=dotprod(pattern,pattern);    /* find pattern magnitude       */
  719.  
  720.     forall(ci,ncom)     /* for all the committees in the network...     */
  721.  
  722.         if(decsn[ci]!=class[ci]) {      /* if the committee goofed up,  */
  723.             goofed=TRUE;                /* then say so,                 */
  724.             pats_missed++;              /* count misrecognized pattern, */
  725.             sway_tlus(ci);              /* and change enough tlu's
  726.                * so it won't goof up on this pattern next time ! */
  727.         }
  728.  
  729.     if(goofed) {                            /* did we goof?             */
  730.         missed++;                           /* yes, count the boo boo!  */
  731.         if(log_level>=2) {                  /* if detail requested,     */
  732.             printf("\n");                   /* start a new line         */
  733.             show_bits("siloam ",decsn);     /* show machine's decision  */
  734.             show_bits("really ",class);     /* display what really is   */
  735.         }
  736.     }
  737. }
  738.  
  739. /************************************************************************
  740.  *
  741.  *    T O T C O N S  --  T o t a l    N u m b e r   O f   C o n n e c t s
  742.  *
  743.  ************************************************************************/
  744.  
  745. int totcons() {                         /* count total # of connections */
  746.  
  747.     committee  *n=net;                  /* neural network pointer       */
  748.     tlu        *c,                      /* committee pointer            */
  749.                 t;                      /* tlu pointer                  */
  750.     int         i,j,k,                  /* loop indices                 */
  751.                 no=0;                   /* totalizer accumulator        */
  752.  
  753.     forall(i,ncom) { c=n++->wtpt;       /* for each committee...        */
  754.         forall(j,ntlu) { t=*c++;        /* for each tlu in the committee*/
  755.             forall(k,dim-1)             /* for each element in the tlu  */
  756.                 if(*t++!=0) no++;       /* count it if it is connected  */
  757.         }
  758.     }
  759.     return(no);                         /* return the count             */
  760. }
  761.  
  762. /************************************************************************
  763.  *
  764.  *   S I L O A M    O u t s i d e    C o n t r o l    S t r u c t u r e
  765.  *
  766.  ************************************************************************/
  767.  
  768. void siloam() {     /* outside control structure for pattern recognizer */
  769.  
  770.     long start,stop;    /* timer value cells for benchmarking           */
  771.     int  cons,new,old=0;/* connection counters                          */
  772.  
  773.     read_header();      /* read header information in the training file */
  774.  
  775.     initialize();       /* allocate the committees of TLUs and
  776.                          * initialize the weight points randomly */
  777.  
  778.     radius_statistics();/* print starting radius statistics             */
  779.  
  780.     npass=0;            /* initialize pass counter                      */
  781.     start=time(NULL);   /* remember start time                          */
  782.  
  783.     do {                /* start over in training file,
  784.                          * we made a mistake... */
  785.  
  786.         missed=0;       /* reset misrecognition counter                 */
  787.  
  788.         read_header();      /* rewind training file
  789.                              * and skip over header information... */
  790.  
  791.         while(read_pattern()) { /* keep reading patterns until we've
  792.           * done the entire training file and recognized them all */
  793.  
  794.             recognize();        /* attempt to recognize the pattern     */
  795.  
  796.             train();            /* adjust any weights necessary to get
  797.                                  * the correct recognition if we goofed */
  798.  
  799.             if(goofed&&start_over) break;   /* select training strategy */
  800.  
  801.         }                   /* end of while loop to read next pattern   */
  802.  
  803.         npass++;                        /* increment pass counter       */
  804.         if(log_level>=1) {              /* give pass summary report     */
  805.             cons=totcons();             /* count the connections        */
  806.             new=cons-old;               /* compute how many new ones    */
  807.             old=cons;                   /* remember for next time       */
  808.             printf("\npass # %d    missed %d   cons=%d   new=%d",
  809.                      npass,        missed,     cons,     new);
  810.         }
  811.             
  812.  
  813.     } while(missed);        /* end of do loop to train network          */
  814.  
  815.     stop=time(NULL);        /* get stop time                            */
  816.  
  817.     /***************** print end of run summary *************************/
  818.  
  819.     printf("\n");
  820.     printf("\ntraining completed in %ld seconds.\n",stop-start);
  821.     printf("\nnumber of committees:  %d",ncom             );
  822.     printf("\nnumber of tlus total:  %d",ncom*ntlu        );
  823.     printf("\nnumber of elements:    %d",ncom*ntlu*dim    );
  824.     printf("\nnumber of connections: %d",totcons()        );
  825.     printf("\n");
  826.  
  827.     printf("\nnumber of passes thru file: %d",npass);
  828.     printf("\nnumber of patterns in file: %d",pats_so_far );
  829.     printf("\nnumber of mis-recognitions: %d",pats_missed );
  830.     printf("\nnumber of tlu adjustments:  %d",tlus_trained);
  831.     printf("\nmaximum element magnitude:  %f",(float)maxel);
  832.     printf("\n");
  833.  
  834.     radius_statistics();    /* print ending radius statistics           */
  835.  
  836. }
  837.  
  838.  
  839. /************************************************************************
  840.  *
  841.  *        M A I N    P r o g r a m    S t a r t s    H e r e
  842.  *
  843.  ************************************************************************/
  844.  
  845. main(paramct,params)    /********** main program entry point ************/
  846.  
  847. int  paramct;           /* number of parameters on command line         */
  848. char *params[];         /* array of pointers to strings for each param  */
  849.  
  850. {
  851.     int i;              /* array index variable                         */
  852.  
  853.     banner();           /* print program name, version, & release date  */
  854.  
  855.     printf("\nInvoked By:");                    /* show how the program */
  856.     for(i=1;i<=paramct;i++) printf(" %s",params[i]); /* was started up! */
  857.     printf("\nelement type is %s",eltype);      /* show arithmetic used */
  858.     printf("\n");
  859.  
  860.     /********************** parse the command line **********************/
  861.  
  862.     if(paramct==1) help();  /* if no params, then give help and quit !  */
  863.     patname[0]=0;           /* else set pattern filename to null string */
  864.  
  865.     for (i=1;i<paramct;i++) {           /* for each parameter...        */
  866.  
  867.         if('-'==params[i][0])               /* is it an option ?        */
  868.  
  869.             switch(toupper(params[i][1])) { /* yes, which one ?         */
  870.  
  871.                 kase('O',start_over=TRUE)               /* strategy     */
  872.                 kase('L',log_level=atoi(¶ms[i][2])) /* log detail   */
  873.                 kase('T',ntlu=atoi(¶ms[i][2]))      /* # of TLUs    */
  874.                 kase('R',radius=atof(¶ms[i][2]))    /* init radius  */
  875.                 kase('I',corr_incr=atoi(¶ms[i][2])) /* fixed incr   */
  876.                 kase('A',absolute=TRUE)                 /* absolute     */
  877.                 kase('F',fraction=atof(¶ms[i][2]))  /* fractional   */
  878.             }
  879.  
  880.         /******************* parse filename *****************************/
  881.  
  882.         else if(index(¶ms[i][0],'.'))   /* is '.' in it?            */
  883.             move(¶ms[i][0],patname);    /* yes, pattern file        */
  884.  
  885.         else move(".PAT",                   /* no, default extension is */
  886.             move(¶ms[i][0],patname));   /* '.pat' for pattern file  */
  887.     }
  888.  
  889.  
  890.     /**************** check for command line errors *********************/
  891.  
  892.     if(patname[0]==0)       /* check for missing pattern file name      */
  893.         abort(
  894.         "pattern filename not specified!");
  895.  
  896.     if(ntlu==0)             /* check for missing number of TLUs         */
  897.         abort(
  898.         "number of TLUs per committee not specified!");
  899.  
  900.  
  901.     /************************* open pattern file ************************/
  902.  
  903.     if(!(pat=fopen(patname,"r")))           /* if open fails, abort     */
  904.         abort(
  905.         "can't open pattern file!");
  906.  
  907.  
  908.     /********* perform the training and recognition algorithm ***********/
  909.  
  910. /*  srand(1);  */   /* make random number generator repeatable --
  911.                      * ...this may be removed, if desired, after the
  912.                      * debug phase is complete! */
  913.  
  914.     siloam();       /* call the outside control structure for the
  915.                      * trainable pattern recognizer. */
  916. }
  917.